package com.varma.android.aws.webserver;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import org.apache.http.HttpException;
import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.DefaultHttpResponseFactory;
import org.apache.http.impl.DefaultHttpServerConnection;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.HttpRequestHandlerRegistry;
import org.apache.http.protocol.HttpService;
import org.apache.http.protocol.ResponseConnControl;
import org.apache.http.protocol.ResponseContent;
import org.apache.http.protocol.ResponseDate;
import org.apache.http.protocol.ResponseServer;

import android.content.Context;

public class WebServer extends Thread {
    private static final String SERVER_NAME = "JarDownloadWebServer";
    private static final String ALL_PATTERN = "*";
    
    private boolean isRunning = false;
    private Context context = null;
    public int serverPort = 0;
    
    private BasicHttpProcessor httpproc = null;
    private BasicHttpContext httpContext = null;
    private HttpService httpService = null;
    private HttpRequestHandlerRegistry registry = null;
    
    private Exception exception = null;
    
    public WebServer(Context context){
        super(SERVER_NAME);
        
        this.setContext(context);
        
//        serverPort = Integer.parseInt(pref.getString(Constants.PREF_SERVER_PORT, "" + Constants.DEFAULT_SERVER_PORT));
        httpproc = new BasicHttpProcessor();
        httpContext = new BasicHttpContext();
            
	    httpproc.addInterceptor(new ResponseDate());
	    httpproc.addInterceptor(new ResponseServer());
	    httpproc.addInterceptor(new ResponseContent());
	    httpproc.addInterceptor(new ResponseConnControl());
	
	    httpService = new HttpService(httpproc, new DefaultConnectionReuseStrategy(), new DefaultHttpResponseFactory());
	
	            
	    registry = new HttpRequestHandlerRegistry();
	    
	    registry.register(ALL_PATTERN, new HttpHandler(context));
	    
	    httpService.setHandlerResolver(registry);
    }
    
    @Override
    public void run() {
        super.run();
        
        try {
            ServerSocket serverSocket = new ServerSocket(serverPort);
            serverPort = serverSocket.getLocalPort();
            wakeUp();
            
            serverSocket.setReuseAddress(true);
            serverSocket.setSoTimeout(20);

            while(isRunning){
                try {
                    final Socket socket = serverSocket.accept();
                    
                    DefaultHttpServerConnection serverConnection = new DefaultHttpServerConnection();
            
                    serverConnection.bind(socket, new BasicHttpParams());
                    
                    httpService.handleRequest(serverConnection, httpContext);
                        
                    serverConnection.shutdown();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (HttpException e) {
                    e.printStackTrace();
                }
            }
            
            serverSocket.close();
        } 
        catch (IOException e) {
            exception = e;
        }
        finally {
        	wakeUp();
        }
    }
    
    public synchronized Exception getError(){
    	return exception;
    }
    
    public synchronized void startThread() {
        isRunning = true;
        
        super.start();
        try {
			this.wait();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
    
    private synchronized void wakeUp(){
    	this.notifyAll();
    }
    
    public synchronized void stopThread(){
        isRunning = false;
        wakeUp();
        try {
			this.wait();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }

    public void setContext(Context context) {
        this.context = context;
    }

    public Context getContext() {
        return context;
    }

}
